#include "bmpcliprect.h"
#include "bmpeditor.h"
#include "sclippallette.h"

const char * BMPClipRect::NAME = "ClipRect";
const char * BMPClipRect::getName(){return NAME;}

void BMPClipRect::setDirty(SDL_Surface * a_surface)
{
//	int z = *m_parent->getBMPViewer()->getZoom();
	BMPEditor* bmpe = (BMPEditor*)getContext();
	int z = bmpe->getZoomViewContent()->getZoom();
	m_toolOnScreen.inset(-z);
	MouseTool::setDirty(0);
	m_toolOnScreen.inset(z);
}

void BMPClipRect::setToolRectangle(const SRect & a_rect)
{
	m_pointA.set(a_rect.getMin());
	m_pointB.set(a_rect.getMax());
	m_tool.setFromPoints(m_pointA, m_pointB);
	BMPEditor* bmpe = (BMPEditor*)getContext();
	ZoomViewPanel * bv = bmpe->getZoomViewContent();
	m_toolOnScreen.set(bv->getViewAreaOfPixel(m_tool.getMin()));
	m_toolOnScreen.w *= m_tool.getWidth();
	m_toolOnScreen.h *= m_tool.getHeight();
}

void BMPClipRect::updateCursor(const SPoint & a_mouse)
{
	m_lastMousePositionUpdated = a_mouse;
	BMPEditor* bmpe = (BMPEditor*)getContext();
	ZoomViewPanel * bv = bmpe->getZoomViewContent();
	m_pixel = bv->pixelPointedAt(a_mouse);
	int oldEdgeSelection = m_edgeState;
	switch(m_state)
	{
	case DONE:
		// check to see if an edge is selected
		if(!m_tool.isZero() && m_tool.insetted(-1).contains(m_pixel))
		{
			// left edge
			int dist = m_pixel.getField(SPoint::X)-m_tool.getField(SRect::MIN_X);
			if(dist < 0 && dist >= -1)	m_edgeState |= EDGE_MINX;
			else						m_edgeState &= ~EDGE_MINX;
			// right edge
			dist = m_pixel.getField(SPoint::X)-m_tool.getField(SRect::MAX_X);
			if(dist > -1 && dist <= 0)	m_edgeState |= EDGE_MAXX;
			else						m_edgeState &= ~EDGE_MAXX;
			// top edte
			dist = m_pixel.getField(SPoint::Y)-m_tool.getField(SRect::MIN_Y);
			if(dist < 0 && dist >= -1)	m_edgeState |= EDGE_MINY;
			else						m_edgeState &= ~EDGE_MINY;
			// bottom edge
			dist = m_pixel.getField(SPoint::Y)-m_tool.getField(SRect::MAX_Y);
			if(dist > -1 && dist <= 0)	m_edgeState |= EDGE_MAXY;
			else						m_edgeState &= ~EDGE_MAXY;
		}
		else	m_edgeState = EDGE_NONE;
		if(oldEdgeSelection != m_edgeState)
		{
			setDirty(0);
		}
		break;
	case IDLE:		m_pointA = m_pixel;
	case DRAWING:	m_pointB = m_pixel;	break;
	case MOVING:						break;
	case RESIZING:	break;
	}
	m_tool.setFromPoints(m_pointA, m_pointB);
	setToolRectangle(m_tool);
}

/** called when the mouse is pressed */
bool BMPClipRect::pressedTool(const int & a_mouseButton)
{
	if(a_mouseButton != SDL_BUTTON_LEFT)	return false;
	if(m_edgeState != EDGE_NONE)
	{
		m_state = RESIZING;
	}
	else if(!m_tool.isZero() && m_tool.contains(m_pixel))
	{
		m_state = MOVING;
		m_delta = m_pixel.difference(m_tool.getMin());
	}
	else
	{
		// start drawing from scratch
		m_state = IDLE;
		updateCursor(m_lastMousePositionUpdated);
		m_state = DRAWING;
		updateCursor(m_lastMousePositionUpdated);
		m_edgeState = EDGE_NONE;
	}
	return true;
}

/** called as the mouse is dragged */
bool BMPClipRect::draggedTool(const int & a_mouseButton)
{
	if(a_mouseButton != SDL_BUTTON_LEFT)	return false;
	switch(m_state)
	{
	case IDLE:
	case DRAWING:
		break;
	case MOVING:
		{
			// move the rectangle to keep up with the mouse
			m_tool.setX(m_pixel.getX()-m_delta.getX());
			m_tool.setY(m_pixel.getY()-m_delta.getY());
			// keep the corners updated with the rectangle
			m_pointA.set(m_tool.getMin());
			m_pointB.set(m_tool.getMax());
		}
		break;
	case RESIZING:
		if(m_edgeState & EDGE_MINX){	m_tool.setField(SRect::MIN_X, m_pixel.getField(SPoint::X));	}
		if(m_edgeState & EDGE_MINY){	m_tool.setField(SRect::MIN_Y, m_pixel.getField(SPoint::Y));	}
		if(m_edgeState & EDGE_MAXX){	m_tool.setField(SRect::MAX_X, m_pixel.getField(SPoint::X));	}
		if(m_edgeState & EDGE_MAXY){	m_tool.setField(SRect::MAX_Y, m_pixel.getField(SPoint::Y));	}
		if(m_tool.getField(SRect::MIN_X) > m_tool.getField(SRect::MAX_X))
		{
			m_edgeState ^= EDGE_MINX;
			m_edgeState ^= EDGE_MAXX;
		}
		if(m_tool.getField(SRect::MIN_Y) > m_tool.getField(SRect::MAX_Y))
		{
			m_edgeState ^= EDGE_MINY;
			m_edgeState ^= EDGE_MAXY;
		}
		m_pointA.set(m_tool.getMin());
		m_pointB.set(m_tool.getMax());
		break;
	}
	return false;
}

/** called when the mouse is released */
bool BMPClipRect::releasedTool(const int & a_mouseButton)
{
	if(a_mouseButton != SDL_BUTTON_LEFT)	return false;
	m_state = DONE;
	return true;
}

bool BMPClipRect::handleEvent(const SDL_Event & e)
{
	bool handled = false;
	SPoint move;
	switch(e.type)
	{
	case SDL_KEYDOWN:
		switch(e.key.keysym.sym)
		{
		case SDLK_RETURN:{
			ImageClip newClip;
			BMPEditor* bmpe = (BMPEditor*)getContext();
			newClip.set(bmpe->getBMP(), m_tool);
			bmpe->addClip(newClip);
			if(m_clipPallette)
			{
				m_clipPallette->addClip(newClip);
				// TODO better code to scroll down to show the most recent addition
				m_clipPallette->keyScroll(SPoint(0, -100));
				m_clipPallette->setDirty(0);
			}
			setDirty(0);
			handled = true;
			break;}
		case SDLK_UP:	move.set(0,-1);	break;
		case SDLK_DOWN:	move.set(0, 1);	break;
		case SDLK_LEFT:	move.set(-1,0);	break;
		case SDLK_RIGHT:move.set( 1,0);	break;
		}
		break;
	case SDL_KEYUP:
		switch(e.key.keysym.sym)
		{
		case SDLK_RSHIFT:
		case SDLK_LSHIFT:
			if(m_edgeState != EDGE_NONE)
			{
				m_edgeState = EDGE_NONE;
				handled = true;
				setDirty(0);
			}
		}
	}
	if(!move.isZero())
	{
		SRect area(m_tool);
		bool shiftHeld = (e.key.keysym.mod & KMOD_SHIFT) != 0;
		switch(m_state)
		{
		case IDLE:	break;
		case DONE:
		case DRAWING:
		case MOVING:
		case RESIZING:
			// if shift isn't held, motion is position changing
			if(!shiftHeld && m_edgeState == EDGE_NONE)
			{
				if(e.key.keysym.mod & KMOD_CTRL)
				{
					move.multiply(m_tool.getDimension());
				}
				area.setX(m_tool.getX()+move.getX());
				area.setY(m_tool.getY()+move.getY());
			}else 
			// if shift is held, and bounds selected, motion changes bounds
			if(shiftHeld && m_edgeState != EDGE_NONE){
				SPoint min(area.getMin());
				SPoint max(area.getMax());
				if(m_edgeState & EDGE_MINX){min.addX(move.getX());}
				if(m_edgeState & EDGE_MINY){min.addY(move.getY());}
				if(m_edgeState & EDGE_MAXX){max.addX(move.getX());}
				if(m_edgeState & EDGE_MAXY){max.addY(move.getY());}
				area.setFromPoints(min, max);
			}else
			// if shift is held, possibly select bounds...
			if(shiftHeld)
			{
				// adding to selection horizontally
				if(move.getX() != 0 && !(m_edgeState & EDGE_MINX) && !(m_edgeState & EDGE_MAXX))
				{
					m_edgeState |= (move.getX() > 0)?EDGE_MAXX:EDGE_MINX;
				}
				// adding to selection vertically
				if(move.getY() != 0 && !(m_edgeState & EDGE_MINY) && !(m_edgeState & EDGE_MAXY))
				{
					m_edgeState |= (move.getY() > 0)?EDGE_MAXY:EDGE_MINY;
				}
			}
			if(area.isValid())
			{
				setDirty(0);
				setToolRectangle(area);
				handled = true;
				setDirty(0);
			}
			break;
		}
	}
	if(!handled)
		handled = MouseTool::handleEvent(e);
	return handled;
}

void BMPClipRect::activate()
{
	MouseTool::activate();
//	m_parent->getBMPViewer()->setDirty(0);
	BMPEditor* bmpe = (BMPEditor*)getContext();
	bmpe->getZoomViewContent()->setDirty(0);
}

void BMPClipRect::deactivate()
{
	MouseTool::deactivate();
	//m_parent->getBMPViewer()->setDirty(0);
	BMPEditor* bmpe = (BMPEditor*)getContext();
	bmpe->getZoomViewContent()->setDirty(0);
}

void BMPClipRect::draw(SDL_Surface * a_surface)
{
	BMPEditor* bmpe = (BMPEditor*)getContext();
	BMPZoomViewPanel * bv = (BMPZoomViewPanel*)bmpe->getZoomViewContent();
//	if(m_clipPallette)
	{
		SRect viewArea(VSDL_getClip(a_surface));//*bv->getViewArea());
//		TemplateVectorList<ImageClip> * clips = m_clipPallette->getClips();
		SRect r, drawable;
		BitMaP * bmp = bv->getBMP();
//		for(int i = 0; i < //clips->size()
//			m_clipPallette->getClipCount(); ++i)
//		{
//			if(m_clipPallette->getClip(i)->image == bmp)
//			{
//				r = m_clipPallette->getClip(i)->clip;
////				if(r.intersects(viewArea))
//				{
//					drawable.set(bv->getViewAreaOfPixelRectangle(r));
//					VSDL_drawRect(a_surface, &drawable, -1, 1);
//				}
//			}
//		}
		for(int i = 0; i < bmpe->getClips()->size(); ++i)
		{
			r = bmpe->getClips()->get(i).clip;
//			if(r.intersects(viewArea))
			{
				drawable.set(bv->getViewAreaOfPixelRectangle(r));
				VSDL_drawRect(a_surface, &drawable, -1, 1);
			}
		}
	}
	SRect r(m_toolOnScreen);
	r.clip(*bv->getArea());
	if(r.isValid())
	{
		int z = bv->getZoom();
		int i = 1;
		r.inset(-i);
		BMPEditor* bmpe = (BMPEditor*)getContext();
		Uint32 color = bmpe->getPallette()->getSelectedColor(BMPPalletteManager::COLOR_OFF,
			a_surface->format);
		VSDL_drawRectBroken(a_surface, &r, -1, i, z);
		SRect edge;
		if(m_edgeState & EDGE_MINX){	edge.set(r.x-z+i, r.y, z-i, r.h);	VSDL_drawRect(a_surface, &edge, -1, 1);	}
		if(m_edgeState & EDGE_MINY){	edge.set(r.x, r.y-z+i, r.w, z-i);	VSDL_drawRect(a_surface, &edge, -1, 1);	}
		if(m_edgeState & EDGE_MAXX){	edge.set(r.x+r.w, r.y, z-i, r.h);	VSDL_drawRect(a_surface, &edge, -1, 1);	}
		if(m_edgeState & EDGE_MAXY){	edge.set(r.x, r.y+r.h, r.w, z-i);	VSDL_drawRect(a_surface, &edge, -1, 1);	}
	}
}